package com.testapp.bluetoothtest08.cipher.tool;


import com.testapp.bluetoothtest08.cipher.entity.CheckData;
import com.testapp.bluetoothtest08.cipher.entity.ScanCodeFirstRequest;
import com.testapp.bluetoothtest08.cipher.entity.ScanCodeSecondRequest;
import com.testapp.bluetoothtest08.cipher.entity.TrackParameter;
import com.testapp.bluetoothtest08.common.CustomException;

import lombok.AllArgsConstructor;

import java.math.BigInteger;


@AllArgsConstructor
public class CheckTools {

    Parameter parameter;

    public CheckData checkSPK2(ScanCodeFirstRequest requestFirst , ScanCodeSecondRequest requestSecond, String challenge){
        CheckData checkData = new CheckData();
        String c_ = "";
        c_ += challenge + requestFirst.A_ + requestFirst.T + requestFirst.ic + requestFirst.SN + requestFirst.D
                + requestFirst.T1 + requestFirst.T2;
        BigInteger numc = new BigInteger(requestSecond.c);
        for (int i = 0; i < requestSecond.s.size(); i++) {
            checkData.bigIntegers.add(new BigInteger(requestSecond.s.get(i)));
        }
        checkData.A_ = new BigInteger(requestFirst.A_);
        checkData.T = new BigInteger(requestFirst.T);
        checkData.T1 = new BigInteger(requestFirst.T1);
        checkData.T2 = new BigInteger(requestFirst.T2);
        checkData.ic = new BigInteger(requestFirst.ic);
        checkData.SN = new BigInteger(requestFirst.SN);
        checkData.D = new BigInteger(requestFirst.D);
        int flag = requestFirst.flag;
        boolean flag2 = requestFirst.flag2;
        BigInteger p11 = parameter.Qrn.A.modPow(numc,parameter.N).multiply(checkData.A_.modPow(checkData.bigIntegers.get(0)               //a^(c)*A'^(s1-c*2^(gama)) mod n
                .subtract(numc.multiply(Parameter.bigTwo.pow(210))),parameter.N)).mod(parameter.N);
        BigInteger p12 = parameter.Qrn.Ax.modPow(checkData.bigIntegers.get(1),parameter.N);                                     //ax^(s2)*as^(s3)*at^(s4)*ai^(s5)*ae^(s6)*ad^(s7)*h^(s8) mod n
        p12 = p12.multiply(parameter.Qrn.As.modPow(checkData.bigIntegers.get(2),parameter.N)).mod(parameter.N);
        p12 = p12.multiply(parameter.Qrn.At.modPow(checkData.bigIntegers.get(3),parameter.N)).mod(parameter.N);
        p12 = p12.multiply(parameter.Qrn.Ai.modPow(checkData.bigIntegers.get(4),parameter.N)).mod(parameter.N);
        p12 = p12.multiply(parameter.Qrn.Ae.modPow(checkData.bigIntegers.get(5),parameter.N)).mod(parameter.N);
        p12 = p12.multiply(parameter.Qrn.Ad.modPow(checkData.bigIntegers.get(6),parameter.N)).mod(parameter.N);
        p12 = p12.multiply(parameter.Qrn.h.modPow(checkData.bigIntegers.get(7),parameter.N)).mod(parameter.N);
        BigInteger p1 = p11.multiply(p12.modInverse(parameter.N)).mod(parameter.N);                                                 //p1 = p11*p12 mod n
        BigInteger p2 = checkData.T.modPow(numc,parameter.Sigma).multiply(parameter.B1.modPow(checkData.bigIntegers.get(3),parameter.Sigma))    //p2 = T^(c) * b1^(s4)*b2^(s9) mod sigma
                .multiply(parameter.B2.modPow(checkData.bigIntegers.get(8),parameter.Sigma)).mod(parameter.Sigma);
        BigInteger p3 = checkData.T1.modPow(numc,parameter.Sigma).multiply(parameter.B1.modPow(checkData.bigIntegers.get(4),parameter.Sigma))   //p3 = T1^(c) * b1^(s5) * b2^(s10) mod sigma
                .multiply(parameter.B2.modPow(checkData.bigIntegers.get(9),parameter.Sigma)).mod(parameter.Sigma);
        BigInteger p4 = checkData.T2.modPow(numc,parameter.Sigma).multiply(checkData.T1.modPow(checkData.bigIntegers.get(5),parameter.Sigma)).mod(parameter.Sigma);//p4 = T2^(c) * T1^(s6) mod sigma
        BigInteger p5 = checkData.T2.modPow(numc,parameter.Sigma).multiply(parameter.B1.modPow(checkData.bigIntegers.get(10),parameter.Sigma))            //p5 = T2^(c)*b1^(s11)*b2^(s12) mod sigma
                .multiply(parameter.B2.modPow(checkData.bigIntegers.get(11),parameter.Sigma)).mod(parameter.Sigma);
        BigInteger p61 = checkData.bigIntegers.get(12).subtract(checkData.bigIntegers.get(5).add(checkData.bigIntegers.get(6))).mod(parameter.K_at);
        BigInteger p6 = parameter.B.modPow(p61,parameter.Sigma);                                                                              //p6 = b^(s13)/(b^(s6)*b^(s7)) mod sigma
        BigInteger p71;

        if (flag2){
            if (flag == 0) {
                p71 = numc.add(checkData.ic.multiply(new BigInteger(requestSecond.s6))).subtract(new BigInteger(requestSecond.s11)
                ).mod(parameter.K_at);
            } else if (flag == 1){
                p71 = numc.add(checkData.ic.multiply(new BigInteger(requestSecond.s6))).subtract(new BigInteger(requestSecond.s11)
                        .add(new BigInteger(requestSecond.s6))).mod(parameter.K_at);
            } else {
                p71 = numc.add(checkData.ic.multiply(new BigInteger(requestSecond.s6))).subtract(new BigInteger(requestSecond.s11)
                        .add(new BigInteger(requestSecond.s6)).add(new BigInteger(requestSecond.s6))).mod(parameter.K_at);
            }
        } else {
            if (flag==0){
                p71 = numc.add(checkData.ic.multiply(checkData.bigIntegers.get(5))).subtract(checkData.bigIntegers.get(10))
                        .mod(parameter.K_at);                                 //p71 = c+ic*s6 - s11-K_at * s14
            } else if (flag == 1){
                p71 = numc.add(checkData.ic.multiply(checkData.bigIntegers.get(5))).subtract(checkData.bigIntegers.get(10)
                        .add(checkData.bigIntegers.get(5))).mod(parameter.K_at);                            //p71 = c+ic*s6 - s11-K_at * s14 -s6
            } else{
                p71 = numc.add(checkData.ic.multiply(checkData.bigIntegers.get(5))).subtract(checkData.bigIntegers.get(10)
                        .add(checkData.bigIntegers.get(5)).add(checkData.bigIntegers.get(5))).mod(parameter.K_at);                            //p71 = c+ic*s6 - s11-K_at * s14 -s6
            }
        }


        BigInteger p7 = parameter.Qrn.A.modPow(p71,parameter.N);                                                                               //p7 = a ^(p71) mod n
        BigInteger p81 = parameter.B1.modPow(numc,parameter.Sigma);
        BigInteger p821 = checkData.bigIntegers.get(2).subtract(numc.multiply(checkData.ic));
        BigInteger p822 = p821.mod(parameter.OrderSignma);
        BigInteger p82 = checkData.SN.modPow(p822,parameter.Sigma);
        BigInteger p83 = parameter.B2.modPow(checkData.bigIntegers.get(14),parameter.Sigma).modInverse(parameter.Sigma);
        BigInteger p8 = p81.multiply(p82).mod(parameter.Sigma).multiply(p83).mod(parameter.Sigma);                                              //p8 = (b1/(SN^(ic)))^(c)*SN^(s3)/(b2^(s15)) mod sigma

        BigInteger p91 = parameter.B2.modPow(numc,parameter.Sigma);
        BigInteger p921 = checkData.bigIntegers.get(3).subtract(numc.multiply(checkData.ic));
        BigInteger p922 = p921.mod(parameter.OrderSignma);
        BigInteger p92 = checkData.SN.modPow(p922,parameter.Sigma);
        BigInteger p93 = parameter.B1.modPow(checkData.bigIntegers.get(15),parameter.Sigma).modInverse(parameter.Sigma);
        BigInteger p9 = p91.multiply(p92).mod(parameter.Sigma).multiply(p93).mod(parameter.Sigma);                                              //p9 = (b2/(SN^(ic)))^(c)*SN^(s4)/(b2^(s16)) mod sigma

        BigInteger p101 = parameter.Qrn.A.multiply(parameter.Qrn.Ai.modPow(checkData.ic,parameter.N)).mod(parameter.N).modInverse(parameter.N);
        BigInteger p102 = checkData.D.multiply(p101).mod(parameter.N).modPow(numc,parameter.N);
        BigInteger p103 = parameter.Qrn.Ax.modPow(checkData.bigIntegers.get(1),parameter.N);
        p103 = p103.multiply(parameter.Qrn.As.modPow(checkData.bigIntegers.get(2),parameter.N)).mod(parameter.N);
        p103 = p103.multiply(parameter.Qrn.At.modPow(checkData.bigIntegers.get(3),parameter.N)).mod(parameter.N);
        p103 = p103.multiply(parameter.Qrn.Ae.modPow(checkData.bigIntegers.get(12),parameter.N)).mod(parameter.N);
        p103 = p103.multiply(parameter.Qrn.Ad.modPow(checkData.bigIntegers.get(6),parameter.N)).mod(parameter.N);
        p103 = p103.multiply(parameter.Qrn.h.modPow(checkData.bigIntegers.get(7),parameter.N)).mod(parameter.N);
        BigInteger p10 = p102.multiply(p103).mod(parameter.N);                                                                              //p10 = (D/(a*ai^(ic)))^(c)*ax^(s2)*as^(s3)*at^(s4)*ae^(s13)*ad^(s7)*h^(s8)mod n
        c_ = c_ + p1.toString() + p2.toString() + p3.toString() + p4.toString() + p5.toString()
                + p6.toString() + p7.toString() + p8.toString() + p9.toString() + p10.toString();

        MD5 md5 = new MD5();
        c_ = md5.start(c_);
        c_ = new BigInteger(c_,16).toString(2).substring(0,parameter.k-1);//可以优化
        c_ = new BigInteger(c_,2).toString();
        if(!requestSecond.c.equals(c_)){
            checkData.flag = false;
            throw new CustomException(400,"SPK2 verification nonconformance");
        }
        return checkData;
    }

    public boolean checkS(CheckData checkData){
        if (!(verifyEpLamK(checkData.bigIntegers.get(0)) && verifyEpLamK(checkData.bigIntegers.get(1)) && verifyEpLamK(checkData.bigIntegers.get(3))
                && verifyEpLamK(checkData.bigIntegers.get(8)) && verifyEpLamK(checkData.bigIntegers.get(9)))) {
            checkData.flag = false;
            throw new CustomException(400,"S verification nonconformance");
            //System.out.println("verify 201 false");
            //return false;
        }
        if (!(verifyEpLsigK(checkData.bigIntegers.get(2)))){
            checkData.flag = false;
            throw new CustomException(400,"S verification nonconformance");
            //System.out.println("verify 397 false");
            //return false;
        }
        if (!(verifyEpLK(checkData.bigIntegers.get(4)) && verifyEpLK(checkData.bigIntegers.get(5)) && verifyEpLK(checkData.bigIntegers.get(6))
                && verifyEpLK(checkData.bigIntegers.get(12)) && verifyEpLK(checkData.bigIntegers.get(13)))) {
            checkData.flag = false;
            throw new CustomException(400,"S verification nonconformance");
            //System.out.println("verify 111 false");
            //return false;
        }
        if (!(verifyEpGamaLamK(checkData.bigIntegers.get(7)))){
            checkData.flag = false;
            throw new CustomException(400,"S verification nonconformance");
            //System.out.println("verify 507 false");
            //return false;
        }
        if (!(verifyEpDoulK(checkData.bigIntegers.get(10)))){
            checkData.flag = false;
            throw new CustomException(400,"S verification nonconformance");
            //System.out.println("verify 126 false");
            //return false;
        }
        if (!(verifyEpLamLK(checkData.bigIntegers.get(11)))){
            checkData.flag = false;
            throw new CustomException(400,"S verification nonconformance");
            //System.out.println("verify 216 false");
            //return false;
        }
        if (!(verifyEpDouLsigK(checkData.bigIntegers.get(14)) && verifyEpDouLsigK(checkData.bigIntegers.get(15)))){
            checkData.flag = false;
            throw new CustomException(400,"S verification nonconformance");
            //System.out.println("verify 699 false");
            //return false;
        }
        return true;

    }

    public boolean checkR(ScanCodeSecondRequest requestSecond,CheckData checkData){
        if (!(new BigInteger(requestSecond.R1).compareTo(parameter.Range5left)== 1)){
            checkData.flag = false;
            throw new CustomException(400,"SN verification nonconformance");
            //System.out.println("R1 left false");
            //return false;
        }
        if (!(new BigInteger(requestSecond.R2).compareTo(parameter.Range5left)== 1)){
            checkData.flag = false;
            throw new CustomException(400,"SN verification nonconformance");
            //System.out.println("R2 left false");
            //return false;
        }
        if (!(new BigInteger(requestSecond.R1).compareTo(parameter.Range5right)== -1)){
            checkData.flag = false;
            throw new CustomException(400,"SN verification nonconformance");
            //System.out.println("R1 right false");
            //return false;
        }
        if (!(new BigInteger(requestSecond.R2).compareTo(parameter.Range5right)== -1)){
            checkData.flag = false;
            throw new CustomException(400,"SN verification nonconformance");
            //System.out.println("R2 right false");
            //return false;
        }
        return true;
    }

    public boolean checkSN(ScanCodeSecondRequest requestSecond,CheckData checkData){
        BigInteger numc = new BigInteger(requestSecond.c);
        BigInteger SN_ = checkData.T.modPow(numc,parameter.Sigma).multiply(parameter.B1.modPow(new BigInteger(requestSecond.R1),parameter.Sigma)).mod(parameter.Sigma)
                .multiply(parameter.B2.modPow(new BigInteger(requestSecond.R2),parameter.Sigma)).mod(parameter.Sigma);
        if(!checkData.SN.equals(SN_)){
            checkData.flag = false;
            throw new CustomException(400,"SN verification nonconformance");
        }
        return true;
    }

    public TrackParameter computerST (BigInteger R1, BigInteger R1_, BigInteger c1, BigInteger c2, BigInteger ic){
        TrackParameter tp = new TrackParameter();
        BigInteger c_inv = c2.subtract(c1);
        BigInteger R_sub = R1.subtract(R1_);
        tp.t = R_sub.divide(c_inv);
        tp.s = c1.multiply(tp.t);
        tp.s = tp.s.add(R1);
        tp.s = tp.s.modInverse(parameter.OrderSignma);
        tp.s = tp.s.subtract(ic);
        tp.bt = parameter.B.modPow(tp.t,parameter.Sigma);
        return tp;
    }

    public boolean verifyEpLamK(BigInteger S){
        if (S.bitLength() == parameter.EpisilonLamK){
            return true;
        } else{
            System.out.println(S.bitLength());
            return false;
        }
    }
    public boolean verifyEpLsigK(BigInteger S){
        if (S.bitLength() == parameter.EpisilonLsigmaK){
            return true;
        } else{
            System.out.println(S.bitLength());
            return false;
        }
    }
    public boolean verifyEpLK(BigInteger S){
        if (S.bitLength() == parameter.EpisilonLK){
            return true;
        } else{
            System.out.println(S.bitLength());
            return false;
        }
    }
    public boolean verifyEpGamaLamK(BigInteger S){
        if (S.bitLength() == parameter.EpisilonGamaLamK){
            return true;
        } else{
            System.out.println(S.bitLength());
            return false;
        }
    }
    public boolean verifyEpDoulK(BigInteger S){
        if (S.bitLength() == parameter.EpisilonDoulK){
            return true;
        } else{
            System.out.println(S.bitLength());
            return false;
        }
    }
    public boolean verifyEpLamLK(BigInteger S){
        if (S.bitLength() == parameter.EpisilonLamLK){
            return true;
        } else{
            System.out.println(S.bitLength());
            return false;
        }
    }
    public boolean verifyEpDouLsigK(BigInteger S){
        if (S.bitLength() == parameter.EpisilonDouLsigK){
            return true;
        } else{
            System.out.println(parameter.EpisilonDouLsigK);
            System.out.println(S.bitLength());
            return false;
        }
    }
}
